#include <iostream>
#include <unordered_map>
#include <unistd.h>
#include <fcntl.h>
#include <cassert>
#include <signal.h>
#include <cstring>
#include <sys/types.h>         
#include <sys/socket.h>
#include "epoll.hpp"
#include "sock.hpp"
#include "Threadpoll.hpp"
struct Data
{
    Sock *_serve;
    Epoll *_epoll;
    std::string _input;
    std::string _output;
};
struct Func
{
    typedef Datathreadpool<std::string> data;
    typedef std::unordered_map<int, Data *>::iterator iterator;
    Func() 
        :_threadpool(new Datathreadpool<std::string>)
    {}
    // 设置非阻塞
    void Setftl(int sock)
    {
        int fl = fcntl(sock, F_GETFL);
        if (fl < 0)
            std::cout << "fcntl fail:" << strerror(errno) << std::endl;
        fcntl(sock, F_SETFL, fl | O_NONBLOCK);
    }
    // 设置端口复用
    void SetPort(int sock)
    {
        int opt = 1;
        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
    } 
    // 处理事件
    void handevent(int num, std::unordered_map<int,Data*>& shine, epoll_event* eve, int sock)
    {
        for (size_t i = 0; i < num; i++)
        {
            // 先查找事件是否在哈希中存在
            if (Find(shine, eve[i].data.fd) == shine.end())
                break;
            if (eve[i].events & EPOLLOUT)
                Write(shine, eve[i].data.fd);
            if (eve[i].events & EPOLLIN)
                Recv(shine, sock, eve[i].data.fd);
        }
    }
    // 写事件
    void Write(std::unordered_map<int,Data*>& shine, int sock)
    {
        auto cur = Find(shine, sock);
        assert(cur != shine.end());
        while(true)
        {
            ssize_t s = send(sock, cur->second->_output.c_str(),cur->second->_output.size(),0);
            if(s > 0)
            {
                std::cout<<"发送成功"<<std::endl;
                cur->second->_output.clear();
            }
            else
            {
                if(errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    std::cout << "缓冲区数据已满或者已发送完成" << std::endl;
                    Button(false, cur, sock);
                    break;
                }
                else if(errno == EINTR)
                {
                    std::cout << "被中断,请重新再试一次" << std::endl;
                    continue;
                }
                else
                {
                    std::cout << "写错误" << std::endl;
                    break;
                }
            }
        }
    }
    // 读事件
    void Recv(std::unordered_map<int,Data*>& shine, int servesock,int sock)
    {
        auto cur = Find(shine, sock);
        assert(cur != shine.end());
        if(cur->first == servesock)
        {
            // 读时间到来并且要加入到epoll模型中
            int newsock = cur->second->_serve->Accept();
            Data *buffer = new Data;
            buffer->_serve = cur->second->_serve;
            Setftl(newsock);
            buffer->_epoll = cur->second->_epoll;
            buffer->_epoll->Ctl(EPOLL_CTL_ADD, newsock, EPOLLIN | EPOLLET);
            shine.emplace(std::make_pair(newsock, buffer));
            // 防止服务器在运行时异常中断
            signal(SIGPIPE, SIG_IGN);
            signal(SIGCHLD, SIG_IGN);
        }
        else
        {
            char buffer[1024];
            memset(buffer, 0, 1024);
            while (true)
            {
                ssize_t s = recv(sock, buffer, 1023, 0);
                if(s > 0)
                {
                    buffer[s] = '\0';
                    cur->second->_input += buffer;
                }
                else if(s == 0)
                {
                    // 对端链接关闭
                    std::cout << "对端关闭链接" << cur->first << std::endl;
                    cur->second->_epoll->Ctl(EPOLL_CTL_DEL, cur->first, 0);
                    delete cur->second;
                    close(cur->first);
                    shine.erase(cur->first);
                    break;
                }
                else
                {
                    // 可能是被中断或者是缓冲区没数据
                    if(errno == EWOULDBLOCK || errno == EAGAIN)
                    {
                        std::cout << "缓冲区没有数据" << std::endl;
                        //处理事件
                        _threadpool.push(cur->second->_input);
                        data *information = _threadpool.back();
                        //这里一定要晚于线程池的线程完成任务的时间，否则会出现此线程快于线程中的线程，导致发送缓冲区为空
                        sleep(3);
                        cur->second->_output = information->message;
                        Button(true, cur, sock);
                        break;
                    }
                    else if(errno == EINTR)
                    {
                        std::cout << "被中断,请重新再试一次" << std::endl;
                        continue;
                    }
                    else
                    {
                        std::cout << "读取错误" << std::endl;
                        break;
                    }
                }
            }
        }    
    }
    // 查找节点是否存在
    iterator Find(std::unordered_map<int,Data*>& shine,int sock)
    {
        auto cur = shine.find(sock);
        if(cur!=shine.end())
            return cur;
        else
            return shine.end();
    }
    // 写事件开关
    void Button(bool button, iterator& cur, int sock)
    {
        // 打开开关
        if(button)
        {
            cur->second->_epoll->Ctl(EPOLL_CTL_MOD, sock, EPOLLIN | EPOLLOUT | EPOLLET);
        }
        // 关闭开关
        else
        {
            cur->second->_epoll->Ctl(EPOLL_CTL_MOD, sock, EPOLLIN | EPOLLET);
        }
    }
public:
    ThreadPool<std::string> _threadpool;
};